package com.ayf.payment.game.api.service.payment;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ayf.payment.game.api.config.RequestConfig;
import com.ayf.payment.game.api.dto.*;
import com.ayf.payment.game.api.dto.ayb.SignPayProductDTO;
import com.ayf.payment.game.api.dto.platform.MerchantPaymentProductDTO;
import com.ayf.payment.game.api.dto.platform.PaymentChannelDTO;
import com.ayf.payment.game.api.entity.Order;
import com.ayf.payment.game.api.entity.Partition;
import com.ayf.payment.game.api.exception.NullSetException;
import com.ayf.payment.game.api.httpclient.HttpUtils;
import com.ayf.payment.game.api.service.MerchantRepository;
import com.ayf.payment.game.api.service.OrderService;
import com.ayf.payment.game.api.service.SignPayProductService;
import com.ayf.payment.game.api.type.OrderStatus;
import com.ayf.payment.game.api.utils.BigDecimalUtil;
import com.ayf.payment.game.api.utils.DateUtils;
import com.swwx.charm.commons.lang.utils.LogPortal;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wwl
 * @date 2020/3/19 14:41
 */
@Service
public class EHBSplitOrderPaymentService extends IPaymentService {
    // 订单状态
    private final static OrderStatus orderStatus = OrderStatus.PROCESSING;

    @Autowired
    private SignPayProductService signPayProductService;

    @Resource
    private MerchantRepository merchantRepository;

    @Autowired
    private OrderService orderService;


    public Map<String, Object> paymentUtil(Order order, Partition partition, String orderCreateStr, String traceId, String redirectUrl) {
        Map<String, Object> result = new HashMap<>(16);
        MerchantCommonDTO merchantDTO = merchantService.getMerchantCommon(partition.getMerchantId());

        MerchantPaymentProductDTO merchantPaymentProductDTO = systemInitialization.productDTO(order.getPayTypeId());
        PaymentChannelDTO paymentChannelDTO = systemInitialization.channelDTO(merchantPaymentProductDTO.getcId());

        BigDecimal actualOrderAmt = getActualOrderAmt(order.getAmount(),paymentChannelDTO.getId(),partition.getMerchantId());

        SignPayProductDTO signPayProduct = signPayProductService.getByMerchantIdAndPayCode(partition.getMerchantId(), paymentChannelDTO.getCode());
        if (signPayProduct == null){
            throw new NullSetException(traceId + "当前商户未开通分账通支付，联系GM开通");
        }
        if (signPayProduct.getCountSignPayProduct() == null || 0 == signPayProduct.getCountSignPayProduct()){
            throw new NullSetException(traceId + "当前商户未开通分账通支付，联系GM开通");
        }
        if (signPayProduct.getApplyStatus() !=2){
            throw new NullSetException(traceId + "分账通支付申请未通过");
        }
        if (StringUtils.isEmpty(signPayProduct.getChannelMerchantId())){
            throw new NullSetException(traceId + "分账通支付通道商户号不存在");
        }
        
        List<Map<String,Object>> splitDetailsList = new ArrayList<>();
        MerchantConfigDTO merchantConfigDTO = merchantRepository.get(order.getMerchantId());
        BigDecimal merchantIncome;
        if (merchantConfigDTO.getMerchantType().equals("LOWER")) {
            BigDecimal rateLower = systemInitialization.proxyGroupSettleRateMap().get(merchantConfigDTO.getSettleIdentificationId()).get(order.getPayTypeId());
            merchantIncome = order.getAmount().multiply(rateLower.multiply(BigDecimal.valueOf(0.01)));
        } else {
            BigDecimal rateMerchant = systemInitialization.settleRateMap().get(merchantConfigDTO.getSettleIdentificationId()).get(order.getPayTypeId());
            merchantIncome = order.getAmount().multiply(rateMerchant.multiply(BigDecimal.valueOf(0.01)));
        }

        Map<String,Object> splitDetailMap = new HashMap<>();
        // GM商户号分账金额
        splitDetailMap.put("merchantId", signPayProduct.getChannelMerchantId());
        splitDetailMap.put("splitAmt", String.valueOf(merchantIncome));
        splitDetailsList.add(splitDetailMap);

        List<OrderSplitDTO> splitDTOList = new ArrayList<>();
        OrderSplitDTO orderSplitDTO = new OrderSplitDTO();
        orderSplitDTO.setMerchantId(String.valueOf(order.getMerchantId()));
        orderSplitDTO.setChannelMerchantId(signPayProduct.getChannelMerchantId());
        orderSplitDTO.setSplitAmt(merchantIncome);
        splitDTOList.add(orderSplitDTO);
        
        //订单支付
        Map<String, String> map = orderCreate(order, merchantDTO, orderCreateStr, traceId,actualOrderAmt,merchantPaymentProductDTO,paymentChannelDTO, splitDetailsList);
        if (map == null) {
            throw new NullSetException("下单失败，请稍后重试！");
        }

        String responseCode = map.get(HttpUtils.RESPONSE_CODE);
        String response_data = map.get(HttpUtils.RESPONSE_DATA);
        BigDecimal randomAmt = BigDecimal.ZERO;
        if ("200".equals(responseCode)) {
            JSONObject data = null;
            try {
                data = JSON.parseObject(response_data);
            } catch (Exception e) {
                LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 分账通下单失败，分账通响应内容格式错误，解析内容发生了{}异常，响应报文:{}", traceId, partition.getMerchantId(), order.getMerchantOrderNo(), e.getClass().getName(), response_data);
                throw new NullSetException("充值失败，请稍后重试！");
            }
            String return_code = data.getString("return_code");
            if ("FAIL".equals(return_code)) {
                LogPortal.error("PAYMENT_PROGRAM_CHANNEL_ORDER_CREATE_FAIL {} 商户ID[{}] 商户订单号[{}] 分账通下单失败，失败原因:{}", traceId, partition.getMerchantId(), order.getMerchantOrderNo(), data.get("return_msg"));
                throw new NullSetException("充值失败，请稍后重试！");
            }
            String err_code = data.getString("err_code");
            if (HttpUtils.SUCCESS_CODE.equals(return_code) && HttpUtils.SUCCESS_CODE.equals(err_code)) {
                Map<String, String> urlMap = null;
                String url = null;
                if (HttpUtils.SUCCESS_CODE.equals(data.get("status"))) {
                    if (data.get("credential") == null) {
                        LogPortal.error("PAYMENT_PROGRAM_CHANNEL_ORDER_CREATE_FAIL {} 商户ID[{}] 商户订单号[{}] 分账通下单失败，失败原因:分账通返回支付凭证为空，请及时处理", traceId, partition.getMerchantId(), order.getMerchantOrderNo());
                        throw new NullSetException("充值失败，请稍后重试！");
                    }
                    try {
                        urlMap = (Map<String, String>) data.get("credential");
                    } catch (Exception e) {
                        LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 支付程序下单失败，失败原因:分账通返回支付凭证转换为Map对象时发生{}异常，请研发人员及时处理", e, traceId, partition.getMerchantId(), order.getMerchantOrderNo(), e.getClass().getName());
                        throw new NullSetException("充值失败，请稍后重试！");
                    }
                } else {
                    LogPortal.error("PAYMENT_PROGRAM_CHANNEL_ORDER_CREATE_FAIL {} 商户ID[{}] 商户订单号[{}] 分账通下单失败，失败原因:分账通返回订单状态为失败", traceId, partition.getMerchantId(), order.getMerchantOrderNo());
                    throw new NullSetException("充值失败，请稍后重试！");
                }
                if ("WECHAT".equals(merchantPaymentProductDTO.getBusinessCode())) {
                    url = urlMap.get("wechat_csb");
                } else if ("ALIPAY".equals(merchantPaymentProductDTO.getBusinessCode())) {
                    url = urlMap.get("alipay_csb");
                } else if ("ANTCREDITPAY".equals(merchantPaymentProductDTO.getBusinessCode())) {
                    url = urlMap.get("alipay_csb");
                }
                if (StringUtils.isNotEmpty(url)) {
                    redisCacheUtil.setObjectToCacheDelaySeconds(order.getMerchantOrderNo(), url, 300L);
                }
                result.put("url", url);
                result.put("merchantOrderNo", order.getMerchantOrderNo());
                result.put("amount",order.getAmount());
                randomAmt = data.getBigDecimal("randomAmt");
                if (randomAmt != null) {
                    order.setRandomAmt(BigDecimalUtil.feeToYuanDown(randomAmt));
                }
                BigDecimal fee = data.getBigDecimal("fee");
                if (fee != null) {
                    order.setFee(BigDecimalUtil.feeToYuanDown(fee));
                }
                String channelOrderNo = data.getString("order_no");
                if (StringUtils.isNotEmpty(channelOrderNo)) {
                    order.setOrderNo(channelOrderNo);
                }
                order.setPayChannleName(paymentChannelDTO.getName());
                order.setPayChannleId(paymentChannelDTO.getId());
                order.setPayTypeName(merchantPaymentProductDTO.getProductName());
                order.setMerchantIncome(BigDecimal.ZERO);
                order.setPlatformIncome(BigDecimal.ZERO);
                order.setFee(BigDecimal.ZERO);
                order.setChannelIncome(BigDecimal.ZERO);
                order.setSplitFlag(1);
                order.setSplitDTOList(splitDTOList);
                orderService.saveOrder(order);
            } else {
                String err_code_desc = data.getString("err_code_desc");
                LogPortal.error("PAYMENT_PROGRAM_CHANNEL_ORDER_CREATE_FAIL {} 商户ID[{}] 商户订单号[{}] 分账通下单失败，分账通错误码[{}] 错误码描述[{}]", traceId, partition.getMerchantId(), order.getMerchantOrderNo(), err_code, err_code_desc);
                throw new NullSetException("充值失败，请稍后重试！");
            }
        } else {
            LogPortal.error("PAYMENT_PROGRAM_CHANNEL_ORDER_CREATE_FAIL {} 商户ID[{}] 商户订单号[{}] 分账通下单失败，HTTP状态码[{}] 响应报文:{}", traceId, partition.getMerchantId(), order.getMerchantOrderNo(), responseCode, response_data);
            throw new NullSetException("充值失败，请稍后重试！");
        }
        if (randomAmt == null){
            randomAmt = BigDecimal.ZERO;
        }
        BigDecimal actualRiskAmt = BigDecimalUtil.yuanToFen(actualOrderAmt.subtract(order.getAmount())).add(randomAmt);
        LogPortal.info("风控金额 actualOrderAmt:{} order.getAmount():{} randomAmt:{} actualRiskAmt:{}",actualOrderAmt,order.getAmount(),randomAmt,actualRiskAmt);
        result.put("randomAmt",actualRiskAmt);//单位 分
        result.put("rechargeNumber", order.getRechargeNumber());
        result.put("partitionName", order.getPartitionName());
        result.put("code", "004");
        redisCacheUtil.setObjectToCacheDelaySeconds("PayBean_".concat(order.getMerchantOrderNo()),result, 300L);
        return result;
    }

    /**
     * 下单
     *
     * @return
     */
    private Map<String, String> orderCreate(Order order, MerchantCommonDTO merchantDTO, String orderCreateStr, String traceId
            , BigDecimal actualOrderAmt, MerchantPaymentProductDTO merchantPaymentProductDTO, PaymentChannelDTO paymentChannelDTO
            , List<Map<String, Object>> splitDetailsList) {
        String merchantOrderNo = order.getMerchantOrderNo();
        Map<String, String> result = null;
        Map<String, Object> orderReqMap = new HashMap<>(16);
        // 商户系统内部订单号，要求64个字符内，只能是数字、大小写字母_-|* 且在同一个商户号下唯一
        orderReqMap.put("merchant_order_no", merchantOrderNo);

        String qq = "";
        if (StringUtils.isNotBlank(merchantDTO.getCustomerQq())) {
            qq = merchantDTO.getCustomerQq();
        } else if (StringUtils.isNotBlank(merchantDTO.getQq())) {
            qq = merchantDTO.getQq();
        }

        // 购买商品的标题，不同支付类型的长度要求不同，具体如下：微信扫码支付：128字节 支付宝扫码支付：128字节
        if (StringUtils.isNotBlank(qq)) {
            orderReqMap.put("product_title", String.format("客服QQ:%s MN:%s", qq, merchantOrderNo));
        } else {
            orderReqMap.put("product_title", String.format("MN:%s", merchantOrderNo));
        }
        // 购买商品的描述信息，要求128个字符内
        orderReqMap.put("product_desc", "客服QQ:" + qq);
        // 符合ISO 4217标准的三位字母代码，默认人民币：CNY
        orderReqMap.put("currency", "CNY");
        // 订单总金额，单位为分
        orderReqMap.put("amount",BigDecimalUtil.yuanToFen(actualOrderAmt));
        // 订单描述，要求300个字符内，不能包含特殊字符:英文逗号，注意：下载对账单会返回此字段数据
        orderReqMap.put("description", "");

        // 交易类型:微信扫码支付:wechat_csb 支付宝扫码支付:alipay_csb 注:区分大小写
        if (merchantPaymentProductDTO.getBusinessCode().equals("WECHAT")) {
            orderReqMap.put("trade_type", "wechat_csb");
        } else if (merchantPaymentProductDTO.getBusinessCode().equals("ALIPAY")) {
            orderReqMap.put("trade_type", "alipay_csb");
        } else if (merchantPaymentProductDTO.getBusinessCode().equals("ANTCREDITPAY")) {
            orderReqMap.put("trade_type", "alipay_csb");
        } else {
            throw new NullSetException("该通道不支持充值，请更换其他通道充值！");
        }
        // 订单生成时间，格式为yyyyMMddHHmmss
        orderReqMap.put("time_start", DateUtils.dateToString(DateUtils.getNowDate(), DateUtils.formatPattern_full_01));
        // 订单失效时间，格式为yyyyMMddHHmmss，此数值为空时，默认1小时。注意:交易类型是微信扫码支付时，过期时间固定为5分钟；交易类型是支付宝扫码时，过期时间固定为2小时
        orderReqMap.put("time_expire", "");
        // 敏感字段加密时使用的密钥，如果报文中有敏感字段，此字段必传，注意:RSA加密之前密钥原文固定16个字节
        orderReqMap.put("encrypted_key", "");
        // 用户IP地址
        orderReqMap.put("user_ip",order.getClientIp());
        orderReqMap.put("splitDetails",JSONObject.toJSONString(splitDetailsList));

        String returnUrl = paymentChannelDTO.getReturnUrl();
        if (StringUtils.isNotEmpty(returnUrl)){
            if (!returnUrl.endsWith("/")){
                returnUrl=returnUrl.concat("/");
            }
            returnUrl=returnUrl.concat("gameapip/v/fzt/pay/notify");
            orderReqMap.put("notify_url",returnUrl);
        }
        String channelPayUrl = paymentChannelDTO.getPaymentUrl();
        if (StringUtils.isEmpty(channelPayUrl)){
            LogPortal.error("{} 失败，通道下单地址不能为空，订单号:{}",traceId,order.getMerchantOrderNo());
            throw new NullSetException(traceId + "下单失败，请稍后重试！");
        }
        if (channelPayUrl.endsWith("/")){
            channelPayUrl=channelPayUrl.substring(0,channelPayUrl.lastIndexOf("/"));
        }
        String url = channelPayUrl + RequestConfig.ORDER_CREATE;
        String reqStr = JSONObject.toJSONString(orderReqMap);
        LogPortal.info("{} 商户ID[{}] 商户订单号[{}] 下单请求参数[{}]", traceId, merchantDTO.getMerchantId(), merchantOrderNo, reqStr);
        try {
            MerchantDTO dto = new MerchantDTO();
            dto.setMerchantSecretKey(paymentChannelDTO.getChannelKey());
            dto.setPrivateKey(paymentChannelDTO.getPlatformPrivateKey());
            dto.setPublicKey(paymentChannelDTO.getChannelPublicKey());
            result = HttpUtils.doPost(traceId, url, reqStr, dto);
            LogPortal.info("{} 商户ID[{}] 商户订单号[{}] 调用分账通下单接口成功，响应报文:{}", traceId, merchantDTO.getMerchantId(), merchantOrderNo, result);
        } catch (Exception e) {
            LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 分账通下单失败，发生了{}异常，错误描述:{}", e, traceId, merchantDTO.getMerchantId(), merchantOrderNo, e.getClass().getName(), e.getMessage());
        }
        if (result != null) {
            result.put("merchantQq", qq);
        }
        return result;
    }

    @Override
    public void queryPayOrder(OrderAndMerchantDTO dto, String traceId) {
        {
            JSONObject data = orderQuery(dto, traceId);
            if (data == null) {
                LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 订单查询结果为空，继续查询", traceId, dto.getMerchantId(), dto.getMerchantOrderNo());
                return;
            }
            Order temp = new Order();
            temp.setMerchantOrderNo(dto.getMerchantOrderNo());
            String status = data.getString("status");
            if ("SUCCESS".equals(status)) {
                Order dbOrder = orderService.selectByMerchantOrderNo(temp.getMerchantOrderNo());
                if (null == dbOrder.getRandomAmt()) {
                    BigDecimal randomAmt = data.getBigDecimal("randomAmt");
                    if (randomAmt != null) {
                        dbOrder.setRandomAmt(BigDecimalUtil.feeToYuanDown(randomAmt));
                    }
                }
                if (dbOrder.getOrderStatus().equals(orderStatus)) {
                    orderService.changeOrderStatusAndMerchantAccount(dbOrder, data);
                    orderService.orderToGetWay(dbOrder);
                    LogPortal.info("{} 商户ID[{}] 商户订单号[{}]OrderQuerTask 通过查询将订单状态由处理中变更为成功", traceId, dto.getMerchantId(), dto.getMerchantOrderNo());
                    wxSendMsgUtils.rechargeSuccess(dbOrder);
                }
            }
        }
    }

    /**
     * 订单查询
     *
     * @return
     */
    private JSONObject orderQuery(OrderAndMerchantDTO dto, String traceId) {
        JSONObject orderReqMap = new JSONObject();
        // 商户系统内部订单号，要求64个字符内，只能是数字、大小写字母_-|* 且在同一个商户号下唯一
        orderReqMap.put("merchant_order_no", dto.getMerchantOrderNo());
        String reqStr = orderReqMap.toJSONString();
        MerchantDTO merchantDTO = new MerchantDTO();
        PaymentChannelDTO paymentChannelDTO = systemInitialization.channelDTO(dto.getPayChannleId());
        merchantDTO.setMerchantSecretKey(paymentChannelDTO.getChannelKey());
        merchantDTO.setPrivateKey(paymentChannelDTO.getPlatformPrivateKey());
        merchantDTO.setPublicKey(paymentChannelDTO.getChannelPublicKey());
        String url = paymentChannelDTO.getPaymentUrl() + RequestConfig.ORDER_QUERY;
        try {
            LogPortal.info("{} 支付程序订单查询 请求参数:{}", traceId, reqStr);
            Map<String, String> result = HttpUtils.doPost(traceId, url, reqStr, merchantDTO, 120);
            if (result == null) {
                LogPortal.info("{} 支付程序订单查询 商户ID[{}] 商户订单号[{}] 分账通返回结果为空，继续查询", traceId, dto.getMerchantId(), dto.getMerchantOrderNo());
                return null;
            }
            String responseCode = result.get(HttpUtils.RESPONSE_CODE);
            String response_data = result.get(HttpUtils.RESPONSE_DATA);
            if ("200".equals(responseCode)) {
                JSONObject data = null;
                try {
                    data = JSON.parseObject(response_data);
                } catch (Exception e) {
                    LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 支付程序调用分账通订单查询失败，分账通响应内容格式错误，解析内容发生了{}异常，响应报文:{}", traceId, dto.getMerchantId(), dto.getMerchantOrderNo(), e.getClass().getName(), response_data);
                    return null;
                }
                String return_code = data.getString("return_code");
                if ("FAIL".equals(return_code)) {
                    String return_msg = data.getString("return_msg");
                    LogPortal.error("PAYMENT_PROGRAM_CHANNEL_ORDER_QUERY_FAIL {} 商户ID[{}] 商户订单号[{}] 支付程序调用分账通订单查询失败，响应错误信息:{}", traceId, dto.getMerchantId(), dto.getMerchantOrderNo(), return_msg);
                    return null;
                }
                String err_code = data.getString("err_code");
                if (HttpUtils.SUCCESS_CODE.equals(return_code) && HttpUtils.SUCCESS_CODE.equals(err_code)) {
                    String channelStatus = data.getString("status");
                    if (HttpUtils.SUCCESS_CODE.equals(channelStatus)) {
                        LogPortal.info("{} 支付程序订单查询成功 订单状态为成功，商户ID[{}] 商户订单号[{}]", traceId, dto.getMerchantId(), dto.getMerchantOrderNo());
                        return data;
                    } else if (HttpUtils.FAIL_CODE.equals(channelStatus)) {
                        LogPortal.info("{} 支付程序订单查询成功 订单状态为失败，商户ID[{}] 商户订单号[{}]", traceId, dto.getMerchantId(), dto.getMerchantOrderNo());
                        return data;
                    } else if (HttpUtils.PROCESSING_CODE.equals(channelStatus)) {
                        LogPortal.info("{} 支付程序订单查询成功 订单状态为处理中，继续查询，商户ID[{}] 商户订单号[{}]", traceId, dto.getMerchantId(), dto.getMerchantOrderNo());
                        return null;
                    } else {
                        LogPortal.info("{} 支付程序订单查询成功 订单状态不明确，继续查询，商户ID[{}] 商户订单号[{}] ", traceId, dto.getMerchantId(), dto.getMerchantOrderNo());
                        return null;
                    }
                } else {
                    String err_code_desc = data.getString("err_code_desc");
                    String channelStatus = data.getString("status");
                    if (StringUtils.isEmpty(channelStatus)) {
                        LogPortal.info("{} 支付程序订单查询成功 订单状态不明确，继续查询，商户ID[{}] 商户订单号[{}] 响应错误码[{}] 错误描述[{}]", traceId, dto.getMerchantId(), dto.getMerchantOrderNo(), err_code, err_code_desc);
                        return null;
                    } else {
                        return data;
                    }
                }
            } else {
                LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 支付程序调用分账通订单查询失败，HTTP状态码[{}] 响应报文:{}", traceId, dto.getMerchantId(), dto.getMerchantOrderNo(), responseCode, response_data);
            }
        } catch (Exception e) {
            LogPortal.error("{} 商户ID[{}] 商户订单号[{}] 支付程序调用分账通订单查询失败，发生了{}异常，错误描述:{}", e, traceId, dto.getMerchantId(), dto.getMerchantOrderNo(), e.getClass().getName(), e.getMessage());
        }
        return null;
    }
}
